package mywebapps.security;

import org.springframework.dao.DataAccessException;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.providers.dao.DaoAuthenticationProvider;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.security.userdetails.UsernameNotFoundException;

import mywebapps.security.dao.UserDao;
import mywebapps.security.dao.UserRoleDao;
import mywebapps.security.model.Role;
import mywebapps.security.model.User;

/**
 * This is a Spring Security implementation of UserDetailsService for user
 * authentication.
 *  
 * @author Paul Rivera (paul_mrivera@yahoo.com)
 *
 */
public class UserDetailsServiceImpl implements UserDetailsService {
    private UserDao userDao;
    private UserRoleDao userRoleDao;

    /**
     * Locates the user in the database based on the username.
     *
     * @param username the username presented to the {@link DaoAuthenticationProvider}
     *
     * @return a fully populated user record (never <code>null</code>)
     *
     * @throws UsernameNotFoundException if the user could not be found or the user has no GrantedAuthority
     * @throws DataAccessException if user could not be found for a repository-specific reason
     */
    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException, DataAccessException {
        User user = userDao.getUser(username);

        if (user != null) {
            UserDetailsImpl details = new UserDetailsImpl();
            details.setUsername(user.getUsername());
            details.setPassword(user.getPassword());
            details.setAccountNonExpired(!user.isExpired());
            details.setAccountNonLocked(!user.isLocked());
            details.setEnabled(user.isEnabled());

            // we are not using this for now
            details.setCredentialsNonExpired(true);

            details.setAuthorities(getUserAuthorities(user.getUserId()));
            return details;
        } else {
            throw new UsernameNotFoundException("The username " + username + " was not found.");
        }
    }

    private GrantedAuthority[] getUserAuthorities(int userId) {
        Role[] roles = userRoleDao.getUserRoles(userId);

        if (roles.length > 0) {
            GrantedAuthority[] authorities = new GrantedAuthority[roles.length];

            for (int i = 0; i < authorities.length; i++) {
                Role role = roles[i];
                GrantedAuthority auth = new GrantedAuthorityImpl(role.getRoleName());
                authorities[i] = auth;
            }

            return authorities;
        }

        return new GrantedAuthority[] {};
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void setUserRoleDao(UserRoleDao userRoleDao) {
        this.userRoleDao = userRoleDao;
    }
}
